﻿namespace ExcelTool{
    using System;
    using System.IO;
    using System.Collections.Generic;
    using libxl;
    public partial class Converter{
        #region 缓存表头名到列数的关系
        Dictionary<string, BookCache> m_bookCache = new Dictionary<string, BookCache>();
        class SheetCache {
            List<string> m_headCache = new List<string>();
            Dictionary<int, List<int>> m_subSheetInfoCache = new Dictionary<int, List<int>>(); //子Sheet ID -> row
            public string sheetName { get; }
            public int shee_index { get; } 
            public Dictionary<int, List<int>> SubSheetInfoCache
            {
                get { return m_subSheetInfoCache; }
            }
            public bool IfHeadRepeated(string name) {
                return m_headCache.Contains(name);
            }
            public int GetHeadColumn(string name) {
                return m_headCache.IndexOf(name);
            }
            public bool SaveHeadCache(string headName) {
                m_headCache.Add(headName);
                return true;
            }
            public bool SaveSubSheetCache(int subSheetId, int row_index) {
                List<int> row_cache;
                if (!m_subSheetInfoCache.TryGetValue(subSheetId, out row_cache))
                {
                    row_cache = new List<int>();
                    m_subSheetInfoCache.Add(subSheetId, row_cache);
                }
                row_cache.Add(row_index);
                return true; 
            }
            public SheetCache(string _n, int _i) {
                sheetName = _n;
                shee_index = _i;
            }
        }
        class BookCache {
            Dictionary<string, SheetCache> m_sheetCache = new Dictionary<string, SheetCache>();

            public bool SaveSheetCache(SheetCache sheetCache) {
                m_sheetCache.Add(sheetCache.sheetName, sheetCache);
                return true;
            }

            public int GetSheetIndex(string name) {
                SheetCache sc;
                if (m_sheetCache.TryGetValue(name, out sc))
                {
                    return sc.shee_index;
                }
                
                return -1;
            }

            public List<int> GetRowList(string subSheetName, int target_id) {
                SheetCache cache;
                if (!m_sheetCache.TryGetValue(subSheetName, out cache)) return null;

                List<int> res;
                if (!cache.SubSheetInfoCache.TryGetValue(target_id, out res)) return null;

                return res;
            }
        }
        //缓存表格信息，建立Sheet名，表头名称的反向索引
        bool tableInfoCache(string tablSource, Book book) {
            BookCache bookCache = new BookCache();
            for(int i = 0; i < book.sheetCount(); i++) {
                Sheet sheet = book.getSheet(i);
                SheetCache sheetCache = new SheetCache(sheet.name, i); 
                for(int col_it = 0; col_it < sheet.lastCol(); col_it++) {
                    if(sheet.cellType(0, col_it) != CellType.CELLTYPE_STRING) {
                        Reporter.PushError("{0}表的Sheet:{1}, 第{2}列的表头类型错误", tablSource, sheet.name, col_it + 1);
                        return false;
                    }

                    string headName = sheet.readStr(0, col_it);
                    if(sheetCache.IfHeadRepeated(headName)) {
                        int repeat_idx = sheetCache.GetHeadColumn(headName);
                        Reporter.PushError("{0}表的Sheet:{1}, 列{2}, {3}的表头名称{4}重复", tablSource, sheet.name, repeat_idx, col_it, headName);
                        return false;
                    }
                    sheetCache.SaveHeadCache(headName);
                }
                //处理子Sheet的数据cache
                if (i > EXCEL_FILE_RULE.MAIN_DATA_SHEET_INDEX)
                {
                    for (int row_it = EXCEL_FILE_RULE.TABLEHEAD_LINE_COUNT; row_it < sheet.lastRow(); row_it++)
                    {
                        try
                        {
                            int subSheetID = Convert.ToInt32(sheet.readNum(row_it, 0));
                            sheetCache.SaveSubSheetCache(subSheetID, row_it);
                        }
                        catch (System.Exception)
                        {
                            Reporter.PushError("缓存Excel: {0}, SubSeet:{1}的ID列失败", sheet.book.FilePath, sheet.name);
                            return false;
                        }
                    }
                }
                bookCache.SaveSheetCache(sheetCache);
            }
            m_bookCache.Add(tablSource, bookCache);
            return true;
        }
        bool GetSheetByName(string bookPath, string sheetName, out Sheet result) {
            result = null;
            BookCache bk;
            if (!m_bookCache.TryGetValue(bookPath, out bk))
            {
                Reporter.PushError("Excel: 【{0}】不存在！", bookPath);
                return false;
            }
            int index = bk.GetSheetIndex(sheetName);
            if (index < 0)
            {
                Reporter.PushError("Excel: 【{0}】中不存在Sheet: 【{1}】", bookPath, sheetName);
                return false;
            }
            try
            {
                Book book = m_excel[bookPath];
                result = book.getSheet(index);
            }
            catch (System.Exception e) 
            {
                Reporter.PushError("GetSubSheetIndex Failed! BookPath: {0}, Exception: {1}", bookPath, e);
                return false;
            }

            return true;
        }
        List<int> GetRowListById(Sheet subSheet, int target_id) {
            BookCache bk;
            if (!m_bookCache.TryGetValue(subSheet.book.FilePath, out bk))
            {
                return null;
            }
            return bk.GetRowList(subSheet.name, target_id);
        }
        #endregion
        #region excel cell操作
        bool ifCellBlank(CellType type) {
            return (type == CellType.CELLTYPE_BLANK || type == CellType.CELLTYPE_EMPTY);
        }
        int readInt(Sheet sheet, int row, int column) {
            CellType type = sheet.cellType(row, column);
            if(ifCellBlank(type)) return 0;
            if (type == CellType.CELLTYPE_NUMBER)
            {
                double num = sheet.readNum(row, column);
                return Convert.ToInt32(num);
            }
            else if (type == CellType.CELLTYPE_STRING)
            {
                string content = sheet.readStr(row, column);
                int res;
                if (int.TryParse(content, out res)) return res;
            }

            throw new System.Exception(string.Format("\n读取单元格Int数据失败 at {0}\n===========================================================", Reporter.MakeExcelCellInfo(sheet, row, column)));
        }
        double readDouble(Sheet sheet, int row, int column) {
            CellType type = sheet.cellType(row, column);
            if(ifCellBlank(type)) return 0;
            if (type == CellType.CELLTYPE_NUMBER)
            {
                double num = sheet.readNum(row, column);
                return num;
            }
            else if (type == CellType.CELLTYPE_STRING)
            {
                string content = sheet.readStr(row, column);
                double res;
                if (double.TryParse(content, out res)) return res;
            }

            throw new System.Exception(string.Format("\n读取单元格Double数据失败 at {0}\n===========================================================", Reporter.MakeExcelCellInfo(sheet, row, column)));
        }
        string readStr(Sheet sheet, int row, int column) {
            CellType type = sheet.cellType(row, column);
            if(ifCellBlank(type)) return string.Empty;
            return sheet.readStr(row, column);
        }
        #endregion
        //计算级联表格的有效行数
        bool sumDataCountByClass() {
            foreach(var item in m_allLib) {
                foreach(XmlClassSet csit in item.Value.class_config) {
                    int total_count = 0;
                    foreach(var datasource in csit.DataSourceList) {
                        Book book;
                        if(m_excel.TryGetValue(datasource.tablename, out book)) {
                            int count = book.getSheet(0).lastRow();
                            if( count > 0) {
                                count--;
                            }
                            total_count += count;
                        }
                    }
                    csit.TotalDataCount = total_count;
                }
            }

            return true;
        }
        public bool LoadExcelFiles() {
            DirectoryInfo dir = new DirectoryInfo(FILE_PATH.EXCEL_DATA_DIR);
            foreach(var item in m_excel) {
                string xlPath = Path.Combine(dir.FullName, item.Key);
                if(!File.Exists(xlPath)) {
                    Reporter.PushError("Excel文件:{0}不存在", xlPath);
                    return false;
                }

                item.Value.load(xlPath);

                if(!tableInfoCache(item.Key, item.Value)) return false;
                
            }
            if(!sumDataCountByClass()) return false;
            return true; 
        }
    }
}
